package game.rule;

import game.util.StringUtils;

import java.util.HashMap;
import java.util.Vector;

public class MorrisGameRule {

	private static HashMap<Integer, Vector<Integer>> id2NeighborList;
	private static Vector<Vector<Integer>> millList;

	static {
		id2NeighborList = new HashMap<Integer, Vector<Integer>>();
		int[][] tmp = new int[][] { { 1, 2, 6 }, { 0, 11 }, { 0, 3, 4, 7 },
				{ 2, 10 }, { 2, 5, 8 }, { 4, 9 }, { 0, 7, 18 },
				{ 2, 6, 8, 15 }, { 4, 7, 12 }, { 5, 10, 14 }, { 3, 9, 11, 17 },
				{ 1, 10, 20 }, { 8, 13 }, { 12, 14, 16 }, { 9, 13 }, { 7, 16 },
				{ 13, 15, 17, 19 }, { 10, 16 }, { 6, 19 }, { 16, 18, 20 },
				{ 11, 19 } };
		for (int i = 0; i < tmp.length; ++i) {
			Vector<Integer> neighbors = new Vector<Integer>();
			for (int j = 0; j < tmp[i].length; ++j) {
				neighbors.add(tmp[i][j]);
			}
			id2NeighborList.put(i, neighbors);
		}
		int[][] mills = new int[][] { { 0, 6, 18 }, { 0, 2, 4 }, { 1, 11, 20 },
				{ 2, 7, 15 }, { 3, 10, 17 }, { 4, 8, 12 }, { 5, 9, 14 },
				{ 6, 7, 8 }, { 9, 10, 11 }, { 12, 13, 14 }, { 13, 16, 19 },
				{ 15, 16, 17 }, { 18, 19, 20 } };
		millList = new Vector<Vector<Integer>>();
		for (int i = 0; i < mills.length; ++i) {
			Vector<Integer> t = new Vector<Integer>();
			for (int j = 0; j < mills[i].length; ++j) {
				t.add(mills[i][j]);
			}
			millList.add(t);
		}
	}

	public static Vector<String> generateMovesOpening(String board) {
		return generateAdd(board);
	}

	public static Vector<String> generateBlackMovesOpening(String board) {
		Vector<String> blackMoveList = generateMovesOpening(StringUtils
				.swapAll(board, 'W', 'B'));
		Vector<String> whiteMoveList = new Vector<String>();
		for (String move : blackMoveList) {
			whiteMoveList.add(StringUtils.swapAll(move, 'W', 'B'));
		}
		return whiteMoveList;
	}

	public static Vector<String> generateMovesMidgameEndgame(String board) {
		if (StringUtils.charCount(board, 'W') == 3) {
			return generateHopping(board);
		} else if (StringUtils.charCount(board, 'W') < 3) {
			return new Vector<String>();
		} else {
			return generateMove(board);
		}
	}

	public static Vector<String> generateBlackMovesMidgameEndgame(String board) {
		Vector<String> blackMoveList = generateMovesMidgameEndgame(StringUtils
				.swapAll(board, 'W', 'B'));
		Vector<String> whiteMoveList = new Vector<String>();
		for (String move : blackMoveList) {
			whiteMoveList.add(StringUtils.swapAll(move, 'W', 'B'));
		}
		return whiteMoveList;
	}

	private static Vector<String> generateAdd(String board) {
		Vector<String> newBoard = new Vector<String>();
		for (int i = 0; i < board.length(); ++i) {
			if (board.charAt(i) == 'x') {
				if (closeMill(i, StringUtils.replace(board, i, 'W'))) {
					newBoard.addAll(generateRemove(StringUtils.replace(board,
							i, 'W')));
				} else {
					newBoard.add(StringUtils.replace(board, i, 'W'));
				}
			}
		}
		return newBoard;
	}

	private static Vector<String> generateHopping(String board) {
		Vector<String> newBoard = new Vector<String>();
		for (int i = 0; i < board.length(); ++i) {
			if (board.charAt(i) == 'W') {
				for (int j = 0; j < board.length(); ++j) {
					if (board.charAt(j) == 'x') {
						if (closeMill(j, StringUtils.swap(board, i, j))) {
							newBoard.addAll(generateRemove(StringUtils.swap(
									board, i, j)));
						} else {
							newBoard.add(StringUtils.swap(board, i, j));
						}
					}
				}
			}
		}
		return newBoard;
	}

	private static Vector<String> generateMove(String board) {
		Vector<String> newBoard = new Vector<String>();
		for (int i = 0; i < board.length(); ++i) {
			if (board.charAt(i) == 'W') {
				Vector<Integer> neighbors = neighbors(i);
				for (int j : neighbors) {
					if (board.charAt(j) == 'x') {
						if (closeMill(j, StringUtils.swap(board, i, j))) {
							newBoard.addAll(generateRemove(StringUtils.swap(
									board, i, j)));
						} else {
							newBoard.add(StringUtils.swap(board, i, j));
						}
					}
				}
			}
		}
		return newBoard;
	}

	private static Vector<String> generateRemove(String board) {
		Vector<String> newBoard = new Vector<String>();
		for (int i = 0; i < board.length(); ++i) {
			if (board.charAt(i) == 'B' && !closeMill(i, board)) {
				newBoard.add(StringUtils.replace(board, i, 'x'));
			}
		}
		return newBoard;
	}

	private static Vector<Integer> neighbors(int loc) {
		return id2NeighborList.get(loc);
	}

	public static boolean closeMill(int loc, String board) {
		for (int i = 0; i < millList.size(); ++i) {
			if (millList.get(i).contains(loc)) {
				boolean find = true;
				for (int j : millList.get(i)) {
					if (board.charAt(j) != board.charAt(loc)) {
						find = false;
						break;
					}
				}
				if (find) {
					return true;
				}
			}
		}
		return false;
	}

}
